﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Server;
using System.IO;

namespace Microsoft.Services.NuGet.Server.Infrastructure
{
    public class BuildPackageStore
        : IPackageStore
    {
        #region Statics

        private static IBuildDetail GetBuild(TfsTeamProjectCollection teamProjectCollection, Uri buildUri)
        {
            teamProjectCollection.EnsureAuthenticated();

            IBuildServer buildServer = teamProjectCollection.GetService<IBuildServer>();

            return buildServer.GetBuild(buildUri);
        }

        private static IEnumerable<IBuildDetail> GetBuilds(TfsTeamProjectCollection teamProjectCollection)
        {
            List<IBuildDetail> buildDetails = new List<IBuildDetail>();

            teamProjectCollection.EnsureAuthenticated();

            ICommonStructureService structure = (ICommonStructureService)teamProjectCollection.GetService(typeof(ICommonStructureService));

            ProjectInfo[] projects = structure.ListProjects();

            IBuildServer buildServer = teamProjectCollection.GetService<IBuildServer>();

            foreach (ProjectInfo project in projects)
            {
                string[] qualities = buildServer.GetBuildQualities(project.Name);

                if (!qualities.Contains<string>("NuGet"))
                {
                    buildServer.AddBuildQuality(project.Name, "NuGet");
                }

                buildDetails.AddRange(buildServer.QueryBuilds(project.Name));
            }

            return (from bd in buildDetails
                    where !bd.IsDeleted && bd.Status == BuildStatus.Succeeded && bd.Quality == "NuGet" && Directory.Exists(bd.DropLocation)
                    orderby bd.FinishTime descending
                    select bd);
        }

        #endregion

        Uri _teamProjectCollectionUrl;

        public BuildPackageStore(string teamProjectCollectionUrl)
            : this(new Uri(teamProjectCollectionUrl, UriKind.Absolute))
        { }

        public BuildPackageStore(Uri teamProjectCollectionUrl)
        {
            _teamProjectCollectionUrl = teamProjectCollectionUrl;
        }

        public string GetFullPath(string path)
        {
            if (!string.IsNullOrEmpty(path) && Uri.IsWellFormedUriString(path, UriKind.RelativeOrAbsolute))
            {
                Uri uri;

                try
                {
                    uri = new Uri(path);
                }
                catch (UriFormatException)
                {
                    uri = null;
                }

                if (uri != null && uri.Scheme.Equals("vstfs", StringComparison.OrdinalIgnoreCase))
                {
                    string buildUri = uri.ToString().Substring(0, uri.ToString().LastIndexOf('/'));

                    using (TfsTeamProjectCollection teamProjectCollection = new TfsTeamProjectCollection(_teamProjectCollectionUrl))
                    {
                        IBuildServer buildServer = teamProjectCollection.GetService<IBuildServer>();
                        IBuildDetail buildDetail = buildServer.GetBuild(new Uri(buildUri));

                        return Path.Combine(buildDetail.DropLocation, uri.ToString().Substring(uri.ToString().LastIndexOf('/') + 1));
                    }
                }
            }

            string fileName = (path.Contains(Path.DirectorySeparatorChar) ? Path.GetFileName(path) : path);

            if (!string.IsNullOrEmpty(fileName))
            {
                foreach (string package in this.Packages)
                {
                    if (package.EndsWith(fileName, StringComparison.OrdinalIgnoreCase))
                    {
                        return this.GetFullPath(package);
                    }
                }
            }

            return path;
        }

        public DateTimeOffset GetLastModified(string path)
        {
            return File.GetLastWriteTimeUtc(GetFullPath(path));
        }

        public IEnumerable<string> Packages
        {
            get
            {
                using (TfsTeamProjectCollection teamProjectCollection = new TfsTeamProjectCollection(_teamProjectCollectionUrl))
                {
                    List<string> packagesProcessed = new List<string>();

                    foreach (IBuildDetail buildDetail in BuildPackageStore.GetBuilds(teamProjectCollection))
                    {
                        DirectoryInfo dir = new DirectoryInfo(buildDetail.DropLocation);

                        if (dir.Exists)
                        {
                            FileInfo[] packages = dir.GetFiles("*.nupkg");

                            foreach (FileInfo package in packages)
                            {
                                if (packagesProcessed.Contains(package.Name, StringComparer.OrdinalIgnoreCase)) continue;

                                packagesProcessed.Add(package.Name);

                                yield return (buildDetail.Uri.ToString() + "/" + package.Name);
                            }
                        }
                    }

                }
            }
        }
    }
}

